<!DOCTYPE html>
<html lang="zh-CN">
  <head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <meta name="description" content="">
  <meta name="keywords" content="">
  
    <link rel="icon" href="/avatar.jpg">
  
    
  <title>在 windows 下使用 clang（不需要重新编译） | 科学君的不科学博客</title>
  <link rel="stylesheet" href="/style.css">
  <link rel="stylesheet" href="/lib/jquery.fancybox.min.css">
  <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
  <script type="text/javascript" src="https://tajs.qq.com/stats?sId=65546304" charset="UTF-8"></script>
  <script>
  (function(){
      var bp = document.createElement('script');
      var curProtocol = window.location.protocol.split(':')[0];
      if (curProtocol === 'https') {
          bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
      }
      else {
          bp.src = 'http://push.zhanzhang.baidu.com/push.js';
      }
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(bp, s);
  })();
  </script>
</head>

<body>
  <header>
  <div class="header-container">
    <a class='logo' href="/">
      <span>科学君的不科学博客</span>
    </a>
    <ul class="right-header">
      
        <li class="nav-item">
          
            <a href="/" class="item-link">首页</a>
          
        </li>
      
        <li class="nav-item">
          
            <a href="/about" class="item-link">关于</a>
          
        </li>
      
        <li class="nav-item">
          
            <a href="/archives" class="item-link">归档</a>
          
        </li>
      
        <li class="nav-item">
          
            <a href="/tags" class="item-link">标签</a>
          
        </li>
      
        <li class="nav-item">
          
            <a href="/atom.xml" class="item-link">FEED 订阅</a>
          
        </li>
      
    </ul>
  </div>
</header>

  <main id='post'>
  <div class="content">
    <article>
      <section class="content markdown-body">
        <h1>在 windows 下使用 clang（不需要重新编译）</h1>
        <div class='post-meta'>
          <i class="fa fa-calendar" aria-hidden="true"></i>
          <time>2016年08月30日</time>
          
          | <i class="fa fa-folder-open-o" aria-hidden="true"></i> 
  <div class="article-category">
    <a class="article-category-link" href="/categories/blog/">blog</a>
  </div>



          
          
          |
          
          <i class="fa fa-tags" aria-hidden="true"></i>
          
          
  <a href="/tags/#emacs" class='tag'>emacs</a>

  <a href="/tags/#LLVM" class='tag'>LLVM</a>

  <a href="/tags/#clang" class='tag'>clang</a>


          
        </div>
        <ul>
<li><a href="#sec-">需求</a></li>
<li><a href="#sec-">如何让 clang 使用 visual studio 2015 的头文件和链接器而不重新编译 clang</a></li>
<li><a href="#sec-">如何让 clang 使用 MinGW64 的头文件和链接器而不重新编译 clang</a></li>
<li><a href="#sec-">如何让 emacs 里面的 company-clang 正常工作</a></li>
</ul>
<h1 id="需求"><a href="#需求" class="headerlink" title="需求"></a>需求<a id="sec-"></a></h1><p>官方网站中的 clang 是使用 Visual Studio 编译的，默认会使用 Visual Studio 的头文件和 链接器，但是如果想要使用 gcc 的头文件或者链接器怎么办？其他的教程大多数要求我们重新 编译 clang，而实际上我们不需要重新编译就可以使用 gcc 的头文件和链接器。在 clang 中， 控制这些的是一个命令行选项： <code>--target</code> 。在这篇博文中，我将介绍如下的内容：</p>
<ol>
<li>如何让 clang 使用 visual studio 2015 的头文件和链接器而不重新编译 clang</li>
<li>如何让 clang 使用 MinGW64 的头文件和链接器而不重新编译 clang</li>
<li>如何让 emacs 里面的 company-clang 正常工作。</li>
</ol>
<p>注意，我的 clang 是 64 位版的 v3.8.1，如果你用的是 32 位版或者别的版本，请参考我的 教程做一些修改。</p>
<h1 id="如何让-clang-使用-visual-studio-2015-的头文件和链接器而不重新编译-clang"><a href="#如何让-clang-使用-visual-studio-2015-的头文件和链接器而不重新编译-clang" class="headerlink" title="如何让 clang 使用 visual studio 2015 的头文件和链接器而不重新编译 clang"></a>如何让 clang 使用 visual studio 2015 的头文件和链接器而不重新编译 clang<a id="sec-"></a></h1><p>如果我们直接使用官方编译版的 clang（我的是 v3.8.1）来编译文件，一般会得到如下的错误：</p>
<pre><code>d:\Sources\cpp&gt;clang 2.cpp
In file included from 2.cpp:1:
In file included from c:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\cstdio:5:
In file included from c:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\yvals.h:8:
c:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\crtdefs.h:10:10: fatal error:
      &apos;corecrt.h&apos; file not found
#include &lt;corecrt.h&gt;
         ^
1 error generated.
</code></pre><p>虽然 clang 会默认使用 msvc 的头文件，但是路径不全，有一些头文件仍然找不到。 根据<a href="https://www.zhihu.com/question/36659299" target="_blank" rel="noopener">https://www.zhihu.com/question/36659299</a> 中的回答，我们可以新建一个 bat 文件，输入：</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">call <span class="string">"%VS140COMNTOOLS%..\..\VC\vcvarsall.bat"</span></span><br><span class="line"><span class="built_in">set</span> PATH=%~dp0bin;%PATH%</span><br><span class="line">cmd /k</span><br></pre></td></tr></table></figure>
<p>然后在打开这个文件弹出的窗口中使用 clang 编译程序。文件第一行调用的 bat 会自动将 msvc 的头文件 目录加进环境变量中，这样 clang 就可以找到头文件了。注意这个环境变量是临时的，只有在打开的这一个 命令提示符窗口才有效。</p>
<p>但是有一些用户（比如我）在编译的的时候会产生另一个奇怪的错误：</p>
<pre><code>d:\Sources\cpp&gt;clang 2.cpp
2-fa894b.o : error LNK2019: 无法解析的外部符号 __acrt_iob_func，该符号在函数 printf 中被引用
2-fa894b.o : error LNK2019: 无法解析的外部符号 __stdio_common_vfprintf，该符号在函数 _vfprintf_l 中被引用
LINK : error LNK2001: 无法解析的外部符号 mainCRTStartup
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\LIB\libcmt.lib : warning LNK4272:库计算机类型“X86”与目标计算机类型“x64”冲突
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\LIB\libcpmt.lib : warning LNK4272:库计算机类型“X86”与目标计算机类型“x64”冲突
a.exe : fatal error LNK1120: 3 个无法解析的外部命令
clang.exe: error: linker command failed with exit code 1120 (use -v to see invocation)
</code></pre><p>这就是 target 出错而导致的问题。</p>
<p>看一下 clang 的版本：</p>
<pre><code>d:\Sources\cpp&gt;clang --version
clang version 3.8.1 (branches/release_38)
Target: x86_64-pc-windows-msvc
Thread model: posix
InstalledDir: c:\Software\LLVM\bin
</code></pre><p>这是官方编译版 clang 安装后的默认版本，可以看到其中的 target 信息是 <code>x86_64-pc-windows-msvc</code> ，这个 target 表示生成的程序类型， 最后的 msvc 表示 clang 会使用 msvc 的头文件和链接器，而前面的 <code>x86_64</code> 表示将使用 64 位的编译器来生成 64 位的程序。但是我的 visual studio 默认安装出来的是 32 位版，target 有误，编译的时候自然会报错了。</p>
<p>其实正确的编译命令是这样： <code>clang --target=i686-w64-windows-msvc 2.cpp</code> ，使用 target 参数来指定生成方式，前面的 <code>i686</code> 表示 使用 32 位的编译器来生成 64 位的程序。这下就可以正常生成而不出错了。</p>
<p>实际上，你可以直接使用开始菜单里面 visual studio 提供的命令行，它会自动配置好目标，在编译的时候就不需要指定 target 了，如下图所示： <img src="16-8-30.png" alt="img"></p>
<p>有时候在编译的时候会弹出一些 char 和 string 的错误，这个我也不知道该怎么解决，出现这种情况建议你改用 MinGW64。</p>
<h1 id="如何让-clang-使用-MinGW64-的头文件和链接器而不重新编译-clang"><a href="#如何让-clang-使用-MinGW64-的头文件和链接器而不重新编译-clang" class="headerlink" title="如何让 clang 使用 MinGW64 的头文件和链接器而不重新编译 clang"></a>如何让 clang 使用 MinGW64 的头文件和链接器而不重新编译 clang<a id="sec-"></a></h1><p>这里我还是建议使用 64 位的 clang 和 gcc 的，因为我只测试了这一种组合。这么做不仅不会有上文中提到的 char 的问题，而且也不需要启用额外的 环境，还可以和 emacs 配合。</p>
<p>上一节我说明了 target 的用法，其实 target 也是可以指定使用 gcc 编译的，指令如下： <code>--target=x86_64-w64-windows-gnu</code> 。</p>
<p>我用的是 mingw64，所以就采用 x86_64 的参数了。在使用的时候还需要指定 include 参数来告诉 clang 头文件的位置。可以用一个 bat 来编译：</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">clang -I c:/Software/MinGW64/mingw64/include/ -I c:/Software/MinGW64/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include -I c:/Software/MinGW64/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include/c++ -I c:/Software/MinGW64/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include/c++/backward -I c:/Software/MinGW64/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include/c++/mingw32 -I c:/Software/MinGW64/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include-fixed --target=x86_64-w64-windows-gnu  %1 %2 %3 %4 %5 %6 %7 %8 %9 -lstdc++ -lsupc++</span><br></pre></td></tr></table></figure>
<p>将上述 bat 命名为 myclang.bat 然后放到 clang 所在目录即可。你可能需要更改一下 mingw 的目录位置。编译的时候只需 <code>myclang 1.cpp</code> 即可。</p>
<p>其实还可以用环境变量来保存 include 目录，更多内容可以参考：<a href="http://blog.csdn.net/gocad/article/details/42297829" target="_blank" rel="noopener">http://blog.csdn.net/gocad/article/details/42297829</a>。 但是这么做的话最后还是需要一个脚本来指定 target。如果 target 也可以放在环境变量里面就好了。我在知乎上提了这个问题，虽然目前还没有有用的 回答：<a href="https://www.zhihu.com/question/50031506" target="_blank" rel="noopener">https://www.zhihu.com/question/50031506</a></p>
<p>用 bat 脚本也有一个坏处：在输入参数的时候等号会被隔成两个参数，比如 <code>myclang 2.cpp --std=c++11</code> ，最后一个参数会被分成两个，这是 cmd 的原因。 你可以在这个参数的两边加上双引号来解决这个问题，但是上面的 bat 最多只能传递 9 个参数的问题就解决不了了。</p>
<p>或者也可以用 powershell，新建一个 <code>myclang.ps1</code> ：</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">clang --target=x86_64-w64-windows-gnu -I c:/Software/MinGW64/mingw64/include/ -I c:/Software/MinGW64/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include -I c:/Software/MinGW64/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include/c++ -I c:/Software/MinGW64/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include/c++/backward -I c:/Software/MinGW64/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include/c++/mingw32 -I c:/Software/MinGW64/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include-fixed  <span class="variable">$args</span> -lstdc++ -lsupc++</span><br></pre></td></tr></table></figure>
<p>这么做的话只能在 powershell 里面调用这个脚本，调用方式和 bat 的一样，支持任意多的参数，而且参数不会被等号分开。注意调用的时候不要加后缀名 ps1。</p>
<p>我还写了一个同样功能的 python3 脚本，调用的方式和 powershell 的一样，需要加上后缀名 <code>.py</code> ，好处是可以在任何地方调用：</p>
<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> sys</span><br><span class="line"><span class="keyword">import</span> subprocess</span><br><span class="line"></span><br><span class="line">cmd = <span class="string">"clang -I c:/Software/MinGW64/mingw64/include/ -I c:/Software/MinGW64/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include -I c:/Software/MinGW64/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include/c++ -I c:/Software/MinGW64/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include/c++/backward -I c:/Software/MinGW64/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include/c++/mingw32 -I c:/Software/MinGW64/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include-fixed --target=x86_64-w64-windows-gnu"</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">main</span><span class="params">(args)</span>:</span></span><br><span class="line">    res = cmd</span><br><span class="line">    <span class="keyword">for</span> a <span class="keyword">in</span> args:</span><br><span class="line">        res += <span class="string">" "</span> + a</span><br><span class="line">    res += <span class="string">" -lstdc++ -lsupc++"</span></span><br><span class="line">    p = subprocess.Popen(res)</span><br><span class="line">    stdout, stderr = p.communicate()</span><br><span class="line">    <span class="keyword">if</span> stdout != <span class="keyword">None</span>:</span><br><span class="line">        print(stdout)</span><br><span class="line">    <span class="keyword">if</span> stderr != <span class="keyword">None</span>:</span><br><span class="line">        print(stderr, file=sys.stderr)</span><br><span class="line">    sys.exit(p.returncode)</span><br><span class="line">    <span class="comment"># print(res)</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:</span><br><span class="line">    main(sys.argv[<span class="number">1</span>:])</span><br></pre></td></tr></table></figure>
<p>总结一下，现在可以轻松用 myclang 命令来编译 cpp 文件了，就像在 Linux 底下使用 clang 一样简单。</p>
<h1 id="如何让-emacs-里面的-company-clang-正常工作"><a href="#如何让-emacs-里面的-company-clang-正常工作" class="headerlink" title="如何让 emacs 里面的 company-clang 正常工作"></a>如何让 emacs 里面的 company-clang 正常工作<a id="sec-"></a></h1><p>如果你使用的是 spacemacs 里面的 c-c++ layer，那这是很好办的。 参见：<a href="http://spacemacs.org/layers/+lang/c-c++/README.html#orgheadline2" target="_blank" rel="noopener">http://spacemacs.org/layers/+lang/c-c++/README.html#orgheadline2</a> 只需要在项目的根目录下面建立一个文件 <code>.company_clang</code> ，然后把之前的参数放进去即可， 比如：</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">--target=x86_64-w64-windows-gnu</span><br><span class="line">-I c:/Software/MinGW64/mingw64/include/</span><br><span class="line">-I c:/Software/MinGW64/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include</span><br><span class="line">-I c:/Software/MinGW64/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include/c++</span><br><span class="line">-I c:/Software/MinGW64/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include/c++/backward</span><br><span class="line">-I c:/Software/MinGW64/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include/c++/mingw32</span><br><span class="line">-I c:/Software/MinGW64/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include-fixed</span><br></pre></td></tr></table></figure>
<p>如果你没有使用 spacemacs 或者不想再每个项目中都单独配置选项的话，可以使用以下的代码：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">;; 设置 windows 底下的 company-clang</span><br><span class="line">;; 系统中必须要有 mingw64，请自行更改其目录位置</span><br><span class="line">(when (spacemacs/system-is-mswindows)</span><br><span class="line">  (with-eval-after-load &apos;company-clang</span><br><span class="line">    (require &apos;nadvice)</span><br><span class="line">    (defconst liu233w//company-clang-additional-clang-args-before</span><br><span class="line">      (replace-regexp-in-string &quot;\n&quot; &quot; &quot;</span><br><span class="line">                                &quot;--target=x86_64-w64-windows-gnu</span><br><span class="line">-I c:/Software/MinGW64/mingw64/include/</span><br><span class="line">-I c:/Software/MinGW64/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include</span><br><span class="line">-I c:/Software/MinGW64/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include/c++</span><br><span class="line">-I c:/Software/MinGW64/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include/c++/backward</span><br><span class="line">-I c:/Software/MinGW64/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include/c++/mingw32</span><br><span class="line">-I c:/Software/MinGW64/mingw64/lib/gcc/x86_64-w64-mingw32/6.2.0/include-fixed&quot;))</span><br><span class="line">    (defconst liu233w//company-clang-additional-clang-args-after</span><br><span class="line">      &quot;-lstdc++ -lsupc++&quot;)</span><br><span class="line">    (advice-add &apos;company-clang--build-complete-args</span><br><span class="line">                :filter-return</span><br><span class="line">                #&apos;(lambda (args)</span><br><span class="line">                    (append</span><br><span class="line">                     (list liu233w//company-clang-additional-clang-args-before)</span><br><span class="line">                     args</span><br><span class="line">                     (list liu233w//company-clang-additional-clang-args-after))))))</span><br></pre></td></tr></table></figure>
<p>company-clang 使用一个函数 <code>company-clang--build-complete-args</code> 来生成传递给 clang 的 额外参数，生成出来的是一个列表。稍后这个参数会被 company 用来调用 clang。这里我使用 一个 advice 来在这个函数的返回值中另加入几项。</p>

      </section>
      <div class="license">
        <a href="http://creativecommons.org/licenses/by-sa/3.0/" rel="license" target="_blank">
          <img src="http://i.creativecommons.org/l/by-sa/3.0/88x31.png" style="border-width:0"
               alt="Creative Commons License" class="center">
        </a>
      </div>
      <p>
        本作品采用
        <a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/deed.zh" target="_blank">
          署名-相同方式共享 4.0 国际
        </a>
        进行许可。欢迎转载、使用、重新发布，但务必保留文章署名
        “不科学的科学君” (Liu233w) 与博客链接：
        <a href="https://liu233w.github.io">https://liu233w.github.io</a>
        ，基于本文修改后的作品务必以相同的许可发布。如有任何疑问，请
        <a href="mailto:wwwlsmcom@outlook.com" target="_blank">与我联系</a>
        。
      </p>
    </article>
    
    <!-- disqus 评论框 start -->
    <div class="comment">
      <div id="disqus_thread" class="disqus-thread">
        <i>加载评论框需要翻墙</i>
      </div>
    </div>
    <!-- disqus 评论框 end -->
    
    
    <!-- livere 评论框 start -->
    <div class="comment">
      <div id="lv-container" data-id="city" data-uid="MTAyMC8zNTE5NS8xMTczMA=="></div>
    </div>
    <!-- livere 评论框 end -->
    
  </div>
  <aside>
    
    <div class="toc-container">
      <h1>目录</h1>
      <div class="content">
        <ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#需求"><span class="toc-number">1.</span> <span class="toc-text">需求</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#如何让-clang-使用-visual-studio-2015-的头文件和链接器而不重新编译-clang"><span class="toc-number">2.</span> <span class="toc-text">如何让 clang 使用 visual studio 2015 的头文件和链接器而不重新编译 clang</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#如何让-clang-使用-MinGW64-的头文件和链接器而不重新编译-clang"><span class="toc-number">3.</span> <span class="toc-text">如何让 clang 使用 MinGW64 的头文件和链接器而不重新编译 clang</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#如何让-emacs-里面的-company-clang-正常工作"><span class="toc-number">4.</span> <span class="toc-text">如何让 emacs 里面的 company-clang 正常工作</span></a></li></ol>
      </div>
    </div>
    
  </aside>
</main>

<!-- disqus 公共JS代码 -->
<script type="text/javascript">
  /* * * CONFIGURATION VARIABLES * * */
  var disqus_shortname = "liu233w";
  var disqus_identifier = "https://liu233w.github.io/2016/08/30/clang-windows.org/";
  var disqus_url = "https://liu233w.github.io/2016/08/30/clang-windows.org/";

  isAgent(getDisqus)

  // determine user agent in China
  function isAgent(cb) {
    var url = '//graph.facebook.com/feed?callback=h';
    var xhr = new XMLHttpRequest();
    var called = false;
    xhr.open('GET', url);
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4 && xhr.status === 200) {
        called = true;
        cb(true);
      }
    };
    xhr.send();
    // timeout 1s, this facebook API is very fast.
    setTimeout(function () {
      if (!called) {
        xhr.abort();
        cb(false)
      }
    }, 1000);
  }

  function getDisqus(isAgent) {
    var dsq = document.createElement('script');
    dsq.type = 'text/javascript';
    dsq.async = true
    dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
    (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq)
  }
</script>
<!-- disqus 公共JS代码 end -->


<script type="text/javascript">
  (function (d, s) {
    var j, e = d.getElementsByTagName(s)[0];

    if (typeof LivereTower === 'function') {
      return;
    }

    j = d.createElement(s);
    j.src = 'https://cdn-city.livere.com/js/embed.dist.js';
    j.async = true;

    e.parentNode.insertBefore(j, e);
  })(document, 'script');
</script>


  <footer>
  <div class="copyright">
    <div>
      &copy; 2019 | Powered by <a href="https://hexo.io" target="_blank">Hexo</a>&nbsp
    </div>
    <div>
      Theme by <a href="https://github.com/lewis-geek/hexo-theme-Aath" target="_blank">Aath</a>
    </div>
  </div>
</footer>


<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<script src="/lib/in-view.min.js"></script>
<script src="/lib/lodash.min.js"></script>
<script>
  var isDown = true
  var oldY = 0
  inView.offset(50)

  document.body.addEventListener('touchstart', function(){});
  
  window.addEventListener('scroll', _.throttle(e => {
    var currentY = window.scrollY
    if((oldY - currentY) < 0) {
      isDown = true
    } else {
      isDown = false
    }
    oldY = currentY
  }, 250))

  $("article img").each(function() {
      var strA = "<a data-fancybox='gallery' href='" + this.src + "'></a>";
      $(this).wrapAll(strA);
  });

  $('.toc-link').each(function() {
      var href = $(this).attr("href");
      
      inView(href).on('exit', () => {
        if (isDown) {
          handleActive(href)
        }
      })

      inView(href).on('enter', () => {
        if (!isDown) {
          handleActive(href)
        }
      })

      this.onclick = function(e) {
        var pos = $(href).offset().top - 10;
        $("html,body").animate({scrollTop: pos}, 300);
        setTimeout(() => {
          handleActive(href)
        }, 350)
        return false
      }
  })

  function handleActive(href) {
    document.querySelectorAll('.toc-link').forEach(elm => {
      elm.classList.remove('active')
    })
    document.querySelector(".toc [href='"+ href +"']").classList.add('active')
  }
</script>
<script src="/lib/jquery.fancybox.min.js"></script>

<script async src="//dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js"></script>

</body>
</html>
